package com.huawei.esdk.uc.device.common;

import java.net.ConnectException;
import java.net.MalformedURLException;
import java.net.URL;
import java.util.Date;
import java.util.UUID;
import java.util.Map.Entry;
import java.util.concurrent.ScheduledFuture;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.TimeoutException;
import org.apache.log4j.Logger;
import com.huawei.ecs.bin.client.BinConnBuilder;
import com.huawei.ecs.bin.client.BinConnMgr;
import com.huawei.ecs.bin.client.BinConnMgr.InitResult;
import com.huawei.ecs.bin.common.AckMsg;
import com.huawei.ecs.bin.common.AskMsg;
import com.huawei.ecs.bin.common.Connection;
import com.huawei.ecs.bin.common.ConnectionMgr;
import com.huawei.ecs.bin.msg.Auth;
import com.huawei.ecs.bin.msg.ServiceAck;
import com.huawei.ecs.bin.service.NotiAtte;
import com.huawei.ecs.bin.service.NotiConf;
import com.huawei.esdk.platform.common.bean.log.InterfaceLogBean;
import com.huawei.esdk.platform.common.utils.ApplicationContextUtil;
import com.huawei.esdk.platform.common.utils.OSUtils;
import com.huawei.esdk.platform.log.itf.IInterfaceLog;
import com.huawei.esdk.uc.device.base.U19DeviceConnectionBase;
import com.huawei.esdk.uc.device.common.constants.SoftCoConstants;
import com.huawei.esdk.uc.device.u19.callback.impl.UCU19AtteCallback;
import com.huawei.esdk.uc.device.u19.callback.impl.UCU19ConfCallback;

/**
 * U19连接和消息管理类
 * 连接和发消息给U19网关
 * <p>
 * @author  c00316442
 * @see  [相关类/方法]
 * @since  [产品/模块版本]
 */
public class U19ClientProvider
{
    private static final Logger LOGGER = Logger.getLogger(U19ClientProvider.class);
    
    private String sap;
    
    private String pwd;
    
    private boolean isSSL;
    
    private int id_ = 0;
    
    private int type_ = Auth.LINKTYPE_VOICE_AND_UC;
    
    public U19ClientProvider(String sap, String pwd, boolean ssl)
    {
        this.sap = sap;
        this.pwd = pwd;
        this.isSSL = ssl;
    }
    
    public Connection openConn()
    {
        String serverIp = null;
        Integer serverPort = null;
        
        if (!sap.startsWith("http"))
        {
            sap = "http://" + sap;
        }
        
        try
        {
            URL serverUrl = new URL(sap);
            serverIp = serverUrl.getHost();
            serverPort = serverUrl.getPort();
        }
        catch (MalformedURLException e)
        {
            LOGGER.warn("URL: " + sap + " format error, init failed.");
            return null;
        }
        
        ConnectionMgr mgr = new BinConnMgr();
        mgr.start();
        
        BinConnBuilder builder = BinConnBuilder.newBuilder();
        builder.withId(id_, type_, pwd);
        builder.withPrimary(serverIp, serverPort);
        builder.withSecondary(serverIp, serverPort);
        builder.withSSL(isSSL);
        builder.withReconnect(5 * 1000, 60 * 10 * 1000);
        Connection conn = builder.build();
        ScheduledFuture<InitResult> future = mgr.initConnection(conn, null);
        U19DeviceConnectionBase.getConnMgrList().add(mgr);
        InitResult result = InitResult.FAILED;
        try
        {
            result = future.get(20, TimeUnit.SECONDS);
        }
        catch (Exception e)
        {
            LOGGER.info("URL: " + sap + " init failed.");
            return null;
        }
        
        if (result == InitResult.OK)
        {
            LOGGER.info("URL: " + sap + " init successfully.");
            return conn;
        }
        
        LOGGER.info("URL: " + sap + " init failed.");
        return null;
    }
    
    @SuppressWarnings("unchecked")
    public <T> T sendMsg(AskMsg askMsg, String gwIp, Class<T> clz)
    {
        boolean connectionError = false;
        String uuid = null;
        
        try
        {
            Connection connection = (Connection)U19DeviceConnectionBase.getDeviceConnectionMap().get(gwIp);
            
            if (null != connection)
            {
                // 记录接口请求日志
                uuid = UUID.randomUUID().toString();
                doInterfaceLogReq(uuid, askMsg.getClassName(), gwIp);
                
                AckMsg ackMsg = connection.sendSyncMsg(askMsg, SoftCoConstants.TIMEOUT);
                
                // 记录接口响应日志
                doInterfaceLogRes(uuid, ((ServiceAck)ackMsg).retCode_);
                
                return (T)ackMsg;
            }
        }
        catch (ConnectException e)
        {
            LOGGER.info("Send message to U19 failed due to connection error");
            connectionError = true;
        }
        catch (TimeoutException e)
        {
            LOGGER.info("Send message to U19 failed due to connection timeout");
            connectionError = true;
        }
        
        try
        {
            ServiceAck ack = (ServiceAck)clz.newInstance();
            
            if (connectionError)
            {
                // 发消息出现异常
                ack.retCode_ = 2130000011;
                doInterfaceLogRes(uuid, ack.retCode_);
            }
            else
            {
                // 连接为空，可能是传入的网关IP不存在或连接初始化失败
                LOGGER.info("Connection is null, could not send message");
                ack.retCode_ = 2130000012;
            }
            
            return (T)ack;
        }
        catch (InstantiationException e)
        {
            LOGGER.info("Response class instance error.");
            return null;
        }
        catch (IllegalAccessException e)
        {
            LOGGER.info("Response class instance error.");
            return null;
        }
    }
    
    public int registerNotification(boolean isReg, String gwIp)
    {
        for (Entry<String, Object> connEntry : U19DeviceConnectionBase.getDeviceConnectionMap().entrySet())
        {
            Connection conn = (Connection)connEntry.getValue();
            if (null != conn)
            {
                if (isReg)
                {
                    conn.registerCallback(NotiConf.class, new UCU19ConfCallback());
                    conn.registerCallback(NotiAtte.class, new UCU19AtteCallback());
                }
                else
                {
                    conn.unregisterCallback(NotiConf.class);
                    conn.unregisterCallback(NotiAtte.class);
                }
            }
        }
        
        return 0;
    }
    
    private void doInterfaceLogReq(String messageId, String interfaceName, String targetIP)
    {
        InterfaceLogBean bean = new InterfaceLogBean();
        bean.setTransactionId(messageId);
        bean.setProduct("UC");
        bean.setInterfaceType("2");
        bean.setProtocolType("BIN");
        bean.setReq(true);
        bean.setName(interfaceName);
        bean.setSourceAddr(OSUtils.getLocalIP());
        bean.setTargetAddr(targetIP);
        bean.setReqTime(new Date());
        
        IInterfaceLog logger = ApplicationContextUtil.getBean("interfaceLogger");
        logger.info(bean);
    }
    
    private void doInterfaceLogRes(String messageId, int resultCode)
    {
        InterfaceLogBean bean = new InterfaceLogBean();
        bean.setTransactionId(messageId);
        bean.setReq(false);
        bean.setRespTime(new Date());
        bean.setResultCode(String.valueOf(resultCode));
        
        IInterfaceLog logger = ApplicationContextUtil.getBean("interfaceLogger");
        logger.info(bean);
    }
}
